package com.ruoyi.coupon.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.ruoyi.common.core.flashpay.constant.CacheKey;
import com.ruoyi.common.core.utils.DateUtils;
import com.ruoyi.common.core.flashpay.utils.FMHtmlUtils;
import com.ruoyi.common.core.flashpay.utils.IdWorker;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.security.auth.AuthUtil;
import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.coupon.domain.TbCoupon;
import com.ruoyi.coupon.domain.TbCouponRecord;
import com.ruoyi.coupon.domain.TbCouponType;
import com.ruoyi.coupon.mapper.TbCouponMapper;
import com.ruoyi.coupon.mapper.TbCouponRecordMapper;
import com.ruoyi.coupon.mapper.TbCouponTypeMapper;
import com.ruoyi.coupon.service.ITbCouponRecordService;
import com.ruoyi.coupon.service.ITbCouponService;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;

/**
 * 优惠券Service业务层处理
 *
 * @author gzc
 * @date 2023-04-24
 */
@Service
public class TbCouponServiceImpl implements ITbCouponService {
    @Autowired
    private TbCouponMapper tbCouponMapper;

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private TbCouponTypeMapper tbCouponTypeMapper;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private ITbCouponRecordService iTbCouponRecordService;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private TbCouponRecordMapper tbCouponRecordMapper;

    /**
     * 查询优惠券
     *
     * @param couponId 优惠券主键
     * @return 优惠券
     */
    @Override
    public TbCoupon selectTbCouponByCouponId(Long couponId) {
        return tbCouponMapper.selectTbCouponByCouponId(couponId);
    }

    /**
     * 查询优惠券列表
     *
     * @param tbCoupon 优惠券
     * @return 优惠券
     */
    @Override
    public List<TbCoupon> selectTbCouponList(TbCoupon tbCoupon) {
        if (AuthUtil.hasRole("common")) {
            return tbCouponMapper.selectTbCouponListByCommon(tbCoupon);
        }
        return tbCouponMapper.selectTbCouponList(tbCoupon);
    }

    /**
     * 新增优惠券
     *
     * @param tbCoupon 优惠券
     * @return 结果
     */
    @Override
    public int insertTbCoupon(TbCoupon tbCoupon) throws IOException {
        if (!SecurityUtils.isAdmin(SecurityUtils.getUserId())) {
            //TODO   商户注册的ID  先用用户ID补充
            tbCoupon.setLesseeId(SecurityUtils.getUserId());
        }
        tbCoupon.setCouponId(idWorker.nextId());
        tbCoupon.setCreateTime(DateUtils.getNowDate());
        tbCoupon.setReceivedNum(0L);
        tbCoupon.setUsedNum(0L);
        int result = tbCouponMapper.insertTbCoupon(tbCoupon);
        TbCouponType tbCouponType = tbCouponTypeMapper.selectTbCouponTypeByCouponTypeId(tbCoupon.getCouponTypeId());
        tbCoupon.setCouponTypeName(tbCouponType.getCouponTypeName());
        Map<String, Object> tbCouponMap = BeanUtil.beanToMap(tbCoupon);
        tbCouponMap.entrySet().removeIf(coupon -> coupon.getValue() == null);
        String loadPath = this.getClass().getResource("/").getPath() + "freemarker/coupon";
        FMHtmlUtils.generatorHtml(loadPath, tbCouponMap, "D:\\webResources\\html\\flashPay\\coupon\\", "coupon.ftl");
        return result;
    }

    /**
     * 修改优惠券
     *
     * @param tbCoupon 优惠券
     * @return 结果
     */
    @Override
    public int updateTbCoupon(TbCoupon tbCoupon) {
        return tbCouponMapper.updateTbCoupon(tbCoupon);
    }

    /**
     * 批量删除优惠券
     *
     * @param couponIds 需要删除的优惠券主键
     * @return 结果
     */
    @Override
    public int deleteTbCouponByCouponIds(Long[] couponIds) {
        return tbCouponMapper.deleteTbCouponByCouponIds(couponIds);
    }

    /**
     * 删除优惠券信息
     *
     * @param couponId 优惠券主键
     * @return 结果
     */
    @Override
    public int deleteTbCouponByCouponId(Long couponId) {
        return tbCouponMapper.deleteTbCouponByCouponId(couponId);
    }

    @Override
    public List<TbCoupon> selectCurrentDayTbCouponList(Date afterOneDay) {
        return tbCouponMapper.selectCurrentDayTbCouponList(afterOneDay);
    }

    @Override
    public void reduceNumByCouponId(Long couponId) {
        tbCouponMapper.reduceNumByCouponId(couponId);
    }

    /**
     * 领取优惠券
     *
     * @param couponId
     * @return
     * @throws ParseException
     */
    @Override
    public AjaxResult receiveCoupon(Long couponId) throws ParseException {
        String couponKey = CacheKey.getCouponKey(couponId);
        Map<Object, Object> couponMap = stringRedisTemplate.opsForHash().entries(couponKey);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        LocalDateTime statTime = sdf.parse((String) couponMap.get("statTime")).toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        LocalDateTime now = LocalDateTime.now();
        //如果是生效日期之前  或者失效日期之后则返回错误信息
        if (now.isBefore(statTime)) {
            return AjaxResult.error("未到领取时间,领取失败!");
        }
        LocalDateTime endTime = sdf.parse((String) couponMap.get("endTime")).toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        if (now.isAfter(endTime)) {
            return AjaxResult.error("优惠券已过期,领取失败!");
        }
        //指定时间内  查询redis缓存是否存在库存   上锁
        RLock rLock = redissonClient.getLock("coupon_" + couponId);
        rLock.lock();
        //查询优惠券领取记录表,当前人是否领取过该优惠券
        Long userId = SecurityUtils.getUserId();
        try {
            int redisNum = Integer.parseInt((String) stringRedisTemplate.opsForHash().get(couponKey, "num"));
            System.out.println("当前数量" + redisNum);
            if (redisNum < 1) {
                return AjaxResult.error("优惠券已无,领取失败!");
            }
            //查询mysql 和 redis中的优惠券记录
            //假设未领取
            boolean flag = false;
            Object redisCouponRecord = stringRedisTemplate.opsForHash().get(CacheKey.getCouponRecordKey(userId), "coupon_" + couponId);
            if (!Objects.isNull(redisCouponRecord)) {
                //redis中的数据不为空  已领取
                flag = true;
            }
            TbCouponRecord tbCouponRecord = iTbCouponRecordService.isReceiveByUserId(couponId, userId);
            if (!Objects.isNull(tbCouponRecord)) {
                //mysql中的优惠券领取记录不为空
                flag = true;
            }
            if (flag) {
                return AjaxResult.error("您已领过,领取失败!");
            }
            //还存在库存则进行-1操作
            stringRedisTemplate.opsForHash().increment(couponKey, "num", -1L);
            //缓存redis信息
            stringRedisTemplate.opsForHash().put(CacheKey.getCouponRecordKey(userId), "coupon_" + couponId, String.valueOf(couponId));
        } finally {
            if (rLock.isLocked() && rLock.isHeldByCurrentThread()) {
                //3. 解锁
                rLock.unlock();
            }
        }
        //发送RabbitMq消息 优惠券表  优惠券领取记录表
        TbCouponRecord tbCouponRecord = new TbCouponRecord();
        tbCouponRecord.setCouponId(couponId);
        tbCouponRecord.setSikgaekId(userId);
        rabbitTemplate.convertAndSend("coupon", tbCouponRecord);
        return AjaxResult.success();
    }

    /**
     * 查询当前登录人的优惠券列表   根据状态  0未使用  1已使用  2已过期
     *
     * @param tbCouponRecord
     * @return
     */
    @Override
    public List<Map<String, Object>> selectMyTbCouponList(TbCouponRecord tbCouponRecord, TbCoupon tbCoupon) {
        //查询 当前人的优惠券领取记录  mysql
        Long userId = SecurityUtils.getUserId();
        tbCouponRecord.setSikgaekId(userId);
        List<TbCouponRecord> tbCouponRecordIds = tbCouponRecordMapper.selectMyTbCouponIds(tbCouponRecord);
        //redis  合并redis中的数据
        if (Objects.isNull(tbCouponRecord.getStatus()) || tbCouponRecord.getStatus() == 0) {
            Map<Object, Object> redisCouponRecordIds = stringRedisTemplate.opsForHash().entries(CacheKey.getCouponRecordKey(userId));
            if (!redisCouponRecordIds.isEmpty()) {
                Set<Object> couponIdKey = redisCouponRecordIds.keySet();
                for (Object couponId : couponIdKey) {
                    Long id = Long.valueOf(String.valueOf(redisCouponRecordIds.get(couponId)));
                    TbCouponRecord tbCouponRecord1 = new TbCouponRecord();
                    tbCouponRecord1.setStatus(0L);
                    tbCouponRecord1.setCouponId(id);
                    tbCouponRecordIds.add(tbCouponRecord1);
                }
            }
        }
        List<Map<String, Object>> resultList = new ArrayList<>();
        if (tbCouponRecordIds.size() > 0) {
            resultList = tbCouponMapper.selectMyTbCouponList(tbCouponRecordIds, tbCoupon);
            //map记录每个当前人的优惠券的状态  key  id   value  status
            Map<String, Object> statusMap = new HashMap<>();
            for (TbCouponRecord tbCouponRecordId : tbCouponRecordIds) {
                statusMap.put(String.valueOf(tbCouponRecordId.getCouponId()), tbCouponRecordId.getStatus());
            }
            //返回的map 添加状态
            for (Map<String, Object> resultMap : resultList) {
                resultMap.put("status", statusMap.get(String.valueOf(resultMap.get("couponId"))));
            }
        }
        return resultList;
    }


}
